'''
Created on 2010/07/06

@author: yukiyonezawa
'''

from pyrfid.Util.Util import Util
import binascii
from pyrfid.asn1.Element import Element

class Decoder(object):
    
    
    
    #UNITED TYPE
    BOOLEAN = '01'
    INTEGER = '02'
    OBJECT_IDENTIFIER = '06'
    OCTET_STRING = '04'
    RELATIVE_OID = '0d'
    SEQUENCE_AND_SEQUENCE_OF = '30'
    
    decodedArray = list()
    
    def __init__(self, data):
#        print data
        self.data = data
        self.processer()
            
    def processer(self):
        
        #print "start Data", self.data        
        while self.data != "": 
            dataType = self.data[:2]
            self.popData(2)
            data = self.data
            value = ""
            length = '00'
            
            if dataType == self.BOOLEAN:
                length = self.lengthDecode()[0]
                value = self.boolDecode()
            elif dataType == self.INTEGER:
                length = self.lengthDecode()[0]
                value = self.intDecode(length)
            elif dataType == self.OBJECT_IDENTIFIER:
                length = self.lengthDecode()[0]
                value = self.oidDecode(length)
            elif dataType == self.OCTET_STRING:
                length = self.lengthDecode()[0]
                value = self.octetStrDecode(length)
            elif dataType == self.RELATIVE_OID:
                pass
            elif dataType == self.SEQUENCE_AND_SEQUENCE_OF:                    
                length = self.lengthDecode()[0]
            else:
#                print dataType
                raise "ERROR"
            print value, "|", length, "|", dataType
            element = Element(value, length, dataType)
            self.decodedArray.append(element)
        
        print self.decodedArray
        return self.decodedArray.reverse()

    def popElement(self):
        if len(self.decodedArray) > 0:
            return self.decodedArray.pop()        
        return ""
    
    def getLengthElement(self):
        return len(self.decodedArray)
    
    def popData(self, lenLenHex):
        self.data = self.data[lenLenHex:]
    
    def lengthDecode(self):
        lenHex = ''
        if self.data[:2] < '7F':
            lenHex = self.data[:2]
            length = eval('0x' + lenHex)
            self.data = self.data[2:]
        else:
            headHex = self.data[:2]
            lenSub = eval('0x' + headHex) - 128
            self.data = self.data[2:]
            subHex = self.data[:2*lenSub]
            length = eval('0x' + subHex)
            self.data = self.data[2*lenSub:]
            lenHex = headHex + subHex
        return (length, lenHex)
    
    def oidDecode(self, oidLen):
        encodedOID = self.data[:2 * oidLen]
        if encodedOID[:2] != '28':
            raise "error"
        
        arcs = [1, 0]
        encodedOID = encodedOID[2:]
        while encodedOID != '':
            if encodedOID[:2] < '80':
                arcs.append(eval('0x' + encodedOID[:2]))
                encodedOID = encodedOID[2:]
            elif encodedOID[:2] >= '81' and encodedOID[2:4] < '80':
                strBit = Util.convertHexToBit(encodedOID[:4])
                arcBin = strBit[1:8].lstrip('0') + strBit[9:]
                arcs.append(Util.convertBinaryToDecimal(arcBin))
                encodedOID = encodedOID[4:]
            elif encodedOID[2:4] >= '80' and encodedOID[4:6] < '80':
                strBit = self.convertHexToBit(encodedOID[:6])
                # print str
                arcBin = strBit[1:8].lstrip('0') + strBit[9:16].lstrip('0') + strBit[17:]
                
                arcs.append(Util.convertBinaryToDecimal(arcBin))
                encodedOID = encodedOID[6:]   
            else:
                raise NotImplementedError
        self.data = self.data[2 * oidLen:]
        return ' '.join(map(str, arcs))
    
    def octetStrDecode(self, length):
        strChar = ''
        
        for i in range(length):
            strChar += binascii.a2b_hex(self.data[:2])
            self.data = self.data[2:]
            
        return strChar
    
    def intDecode(self, length):
        strHex = ''
        newIntBit = ''
        
        if self.data[0] < '80': #Positive integer
            if self.data[0] == '00':
                intHex = self.data[2:2*length]
            else:
                intHex = self.data[:2*length]
            intValue = eval('0x' + intHex)  
        else: #Negative integer
            intBit = ''
            intHex = self.data[:2*length]
            for h in intHex:
                intBit += Util.h2b.get(h)
            intBit = '0' + intBit[1:]
            intValue = eval('0x' + Util.convertBitToHex(intBit)) - \
                       2 ** (len(intBit) - 1)
        self.data = self.data[2*length:]
        return intValue
    
    def boolDecode(self):
        if self.data[:2] == '00':
            self.data = self.data[2:]
            return False
        elif self.data[:2] == 'FF':
            self.data = self.data[2:]
            return True
        else:
            raise "error"